﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using Microsoft.Windows.UserControls.Core.Converters;

namespace Microsoft.Windows.UserControls
{
    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(LoggerViewItem))]
    [TemplatePart(Name = "ItemsHost", Type = typeof(ItemsPresenter))]
    [TemplatePart(Name = "PART_Header", Type = typeof(FrameworkElement))]
    public class LoggerViewItem : TreeViewItem
    {
        public static readonly DependencyProperty StatusProperty = DependencyProperty.Register("Status", typeof(StatusType), typeof(LoggerViewItem), new PropertyMetadata(StatusType.None,OnStatusPropertyChanged));
        
        public StatusType Status
        {
            get
            {
                return (StatusType)base.GetValue(StatusProperty);
            }
            set
            {
                base.SetValue(StatusProperty, value);
            }
        }

        static LoggerViewItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(LoggerViewItem), new FrameworkPropertyMetadata(typeof(LoggerViewItem)));
        }

        public LoggerViewItem() : base()
        {
            base.SetValue(TreeViewItem.IsExpandedProperty, true);
        }

        protected Boolean canUpdateParent = true;
        protected Boolean canUpdateChilds = true;

        static void OnStatusPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var control = sender as LoggerViewItem;
            if (control == null)
                return;
            
            var canContinueStatusChanged = true; 
            if (! DesignerProperties.GetIsInDesignMode(control))
            {
                var treeviewControl = control.GetOwnerControl();
                if (treeviewControl != null)
                {
                    canContinueStatusChanged = treeviewControl.IsLoaded;
                    if (!treeviewControl.IsLoaded && control.canUpdateParent && control.canUpdateChilds)
                    {
                        treeviewControl.StatusPendingUpdateCollection.Add(control);
                    }
                }
            }
            if (canContinueStatusChanged)
                control.OnStatusChanged((StatusType)args.NewValue);
        }

        internal void OnStatusChanged(StatusType statusType)
        {
            if (canUpdateChilds && statusType != StatusType.Mixed)
                foreach (LoggerViewItem item in Items)
                {
                    item.canUpdateParent = false;
                    item.Status = statusType;
                    item.canUpdateParent = true;
                }
        
            if (canUpdateParent)
            {
                var parentControl = ItemsControl.ItemsControlFromItemContainer(this) as  LoggerViewItem; 
                if (parentControl == null)
                    return;

                var status = StatusType.Mixed;
                if (parentControl.Items.Cast<LoggerViewItem>().Where(t => t.Status == StatusType.None).Count() == parentControl.Items.Count)
                    status = StatusType.None;
                else if (parentControl.Items.Cast<LoggerViewItem>().Where(t => t.Status == StatusType.Checked).Count() == parentControl.Items.Count)
                    status = StatusType.Checked;
            
                parentControl.canUpdateChilds = false;
                parentControl.Status = status;
                parentControl.canUpdateChilds = true;
            }
        }

        protected LoggerView GetOwnerControl()
        {
            var parentControl = ItemsControl.ItemsControlFromItemContainer(this);
            if (parentControl is LoggerViewItem)
                parentControl = ((LoggerViewItem)parentControl).GetOwnerControl();
            if (parentControl is LoggerView)
                return parentControl as LoggerView;

            return null;
        }

        public override void OnApplyTemplate()
        {
            var loggerViewControl = GetOwnerControl();
            if (loggerViewControl != null && loggerViewControl.GetBindingExpression( ItemsSourceProperty ) == null)
                    HeaderTemplate = GetHeaderDataTemplate(false);
            base.OnApplyTemplate();
        }

        internal static DataTemplate GetHeaderDataTemplate(Boolean isBindingItemsSource)
        {
            var dataTemplate = new DataTemplate();
            var stackPanelfactory = new FrameworkElementFactory(typeof(StackPanel));
            stackPanelfactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
            stackPanelfactory.SetValue(StackPanel.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
            dataTemplate.VisualTree = stackPanelfactory;
            stackPanelfactory.AppendChild(GetFrameworkElementPath(isBindingItemsSource));
            stackPanelfactory.AppendChild(GetFrameworkElementTextBlock(isBindingItemsSource));
            return dataTemplate;
        }

        static FrameworkElementFactory GetFrameworkElementPath(Boolean isBindingItemsSource)
        {
            var elementFactory = new FrameworkElementFactory(typeof(Path));
            elementFactory.SetValue(Path.HeightProperty, 12.0);
            elementFactory.SetValue(Path.WidthProperty, 12.0);
            elementFactory.SetValue(Path.MarginProperty, new Thickness(0,3.0,6.0,3.0));
            elementFactory.SetValue(Path.StretchProperty, Stretch.Uniform);
            elementFactory.SetValue(Path.FillProperty, SystemColors.ControlTextBrush);
            
            var binding = new Binding() {Path = new PropertyPath("Status")};
            binding.Converter = new LoggerItemViewStatusTypeToPathConverter();
            elementFactory.SetBinding(Path.DataProperty, binding);
            if( !isBindingItemsSource)
                binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(LoggerViewItem), 1);
            return elementFactory;
        }

        static FrameworkElementFactory GetFrameworkElementTextBlock(Boolean isBindingItemsSource)
        {
            var elementFactory = new FrameworkElementFactory(typeof(TextBlock));
            var binding = new Binding() {Path = new PropertyPath("Header")};
            elementFactory.SetBinding(TextBlock.TextProperty, binding);
            if( !isBindingItemsSource )
                binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(LoggerViewItem), 1);
            return elementFactory;
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new LoggerViewItem();
        }
  
        public enum StatusType
        {
            None = 0,
            Mixed = 1,
            Checked = 2,
        }
    }
}